//
//  CLHtmlExtracter.m
//  chanlin
//
//  Created by Ryan on 14-11-13.
//  Copyright (c) 2014年 chanlin. All rights reserved.
//

#import "CLHtmlExtracter.h"

#import <libxml/threads.h>
#import <libxml/parser.h>
#import <libxml/HTMLparser.h>

#import "INHtmlElement.h"
#import "NSObject+sagittarius.h"
#import "INHtmlElementUtil.h"
#import "CLDocCell.h"
#import "NSString+Filter.h"

@implementation CLHtmlExtracter

SGR_DEF_SINGLETION(CLHtmlExtracter)

+ (void)extract4News:(xmlNodePtr)_node array:(NSMutableArray *)_array{
    xmlNode *cur_node = NULL;
   // NSMutableDictionary *dic=[NSMutableDictionary dictionary];
    for (cur_node = _node; cur_node; cur_node = cur_node->next){
        if(cur_node->type==XML_TEXT_NODE && cur_node->content){
            NSString *strText=[NSString stringWithCString:(char *)cur_node->content encoding:NSUTF8StringEncoding];
            strText = [strText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
            if(strText==nil)continue;
            strText = [strText stringByReplacingOccurrencesOfString:@"p>" withString:@""];
            NSString *_nodeParentName = @"";
            if (cur_node->parent && cur_node->parent->name) {
                _nodeParentName = [NSString stringWithCString:(char *)cur_node->parent->name encoding:NSUTF8StringEncoding];
            }
            INHtmlElement *element=[_array lastObject];
            NSDictionary *attrs=[self _parseAttrContentWithNode:_node->parent];
            
            NSString *styleParent=nil;
            NSString *labelParent=nil;
            if(_node->parent && _node->parent->parent &&_node->parent->parent->type== XML_ELEMENT_NODE){
                styleParent=[self _parseAttrContentWithLabels:@"style" andNode:_node->parent->parent];
                [attrs sgrSetObject:styleParent forKey:@"pStyle"];
                if(_node->parent->parent->name){
                    labelParent=[NSString stringWithCString:(char *)_node->parent->parent->name
                                                   encoding:NSUTF8StringEncoding];
                }
            }
            
            [[INHtmlElementUtil sharedInstance] parseAttrStrWitnString:strText
                                                             andLabels:_nodeParentName
                                                        andLastElement:element
                                                        andSuperLabels:labelParent
                                                                  attr:attrs];
            [element.strValue appendString:strText];
            
        }if(cur_node->type==XML_ELEMENT_NODE){
             NSString *str=[NSString stringWithCString:(char *)cur_node->name encoding:NSUTF8StringEncoding];
            // --图片
            if ([@"img" isEqualToString:str]) {
                INHtmlElement *ele= [self extractImgSrc4News:cur_node array:_array];
                [_array addObject:ele];
                
            }else   if([[INHtmlElementUtil sharedInstance] isParagraphLabels:str]){
                // 空白对象会在结束后过滤掉
                
                if([@"br" isEqualToString:str]){
                    INHtmlElement *element=[[INHtmlElement alloc] init];
                    element.attributeEntitys = [[NSMutableArray alloc] init];
                    element.type=HtmlElementTypeText;// 文章
                    [_array addObject:element];
                    NSString *strText=@"      ";
                    
                    [[INHtmlElementUtil sharedInstance] parseAttrStrWitnString:strText
                                                                     andLabels:@"br"
                                                                andLastElement:element
                                                                andSuperLabels:nil
                                                                          attr:nil];
                    [element.strValue appendString:strText];


                }
                
                
                INHtmlElement *lastElement = [_array lastObject];
                if (lastElement == nil || lastElement.type != HtmlElementTypeText || _isStrNotNull(lastElement.strValue)) {
                    INHtmlElement *element=[[INHtmlElement alloc] init];
                    element.attributeEntitys = [[NSMutableArray alloc] init];
                    element.type=HtmlElementTypeText;// 文章
                    [_array addObject:element];
                    
                }
            }

        }
        
        // 递归遍历子属性
        [self extract4News:cur_node->children array:_array ];

    }
    
}

+ (INHtmlElement *)extractImgSrc4News:(xmlNodePtr)_node array:(NSMutableArray *)_array{
    NSString *urlStr = [self _parseAttrContentWithLabels:@"src" andNode:_node];
    if (urlStr.length < 5) {
        return nil;
    }
    INHtmlElement *element=[[INHtmlElement alloc] init];
    element.type=HtmlElementTypeImage; // 图片
    element.strValue=[urlStr mutableCopy];
    element.imgNote=[self _parseAttrContentWithLabels:@"alt" andNode:_node];
    element.imgHeight=[[self _parseAttrContentWithLabels:@"height" andNode:_node] floatValue];
    element.imgWidth=[[self _parseAttrContentWithLabels:@"width" andNode:_node] floatValue];
    if(isnan(element.imgHeight)) element.imgHeight=290.f;
    if(isnan(element.imgWidth)) element.imgWidth=300.f;
    if(element.imgHeight==0||element.imgWidth==0 || isnan(element.imgHeight) || isnan(element.imgWidth)){
        element.imgWidth=290;
        element.imgHeight=300.f;
    }else{
        element.imgHeight=(element.imgHeight/element.imgWidth)*I_DOC_CONTENT_WIDTH;
    }
    return element;
    
}


+ (NSMutableDictionary *)_parseAttrContentWithNode:(xmlNodePtr)_node{
    NSString *contentStr = nil;
    NSMutableDictionary *dic=[NSMutableDictionary dictionary];
    for(xmlAttrPtr attr=_node->properties;attr;attr=attr->next){
        if (attr->type==XML_ATTRIBUTE_NODE){
            NSString *str=[NSString stringWithCString:(char *)attr->name encoding:NSUTF8StringEncoding];
            if(!(attr->children &&attr->children->content)) continue;
            if([@"style" isEqualToString:str]){
                contentStr=[NSString stringWithCString:(char *)attr->children->content encoding:NSUTF8StringEncoding];
                [dic sgrSetObject:contentStr forKey:@"style"];
            }else if([@"href" isEqualToString:str]){
                contentStr=[NSString stringWithCString:(char *)attr->children->content encoding:NSUTF8StringEncoding];
                [dic sgrSetObject:contentStr forKey:@"href"];
            }
        }
    }
    return dic;
}

// 解析出需要的属性内容
+ (NSString *)_parseAttrContentWithLabels:(NSString *)attrName andNode:(xmlNodePtr)_node{
    if (!attrName || [attrName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length < 1) {
        return nil;
    }
    NSString *contentStr = nil;
    for(xmlAttrPtr attr=_node->properties;attr;attr=attr->next){
        if (attr->type==XML_ATTRIBUTE_NODE){
            NSString *str=[NSString stringWithCString:(char *)attr->name encoding:NSUTF8StringEncoding];
            if ([attrName isEqualToString:str]&&
                attr->children &&
                attr->children->content) {
                contentStr=[NSString stringWithCString:(char *)attr->children->content encoding:NSUTF8StringEncoding];
                break;
            }
        }
    }
    return contentStr;
}

+ (NSArray *)parse:(NSString *)htmlSource{
    if(_isStrNULL(htmlSource)) return nil;
    NSData *data=[htmlSource  dataUsingEncoding:NSUTF8StringEncoding];
    if([data length]<20){
        return nil;
    }
    
    const void *s=[data bytes];
    htmlDocPtr doc=htmlReadMemory(s, (int)[data length], "","utf-8", HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
    if (doc==NULL) {
        NSAssert(false,@"html parse fail");
        return nil;
    }
    
    NSMutableArray *arr=[[NSMutableArray alloc] init];
    // 根节点
    htmlNodePtr rootNode=xmlDocGetRootElement(doc);
    [self extract4News:rootNode array:arr ];
    NSMutableArray *array=[NSMutableArray array];
    for(INHtmlElement *element in arr){
        if(element.type==HtmlElementTypeText &&
           _isStrNULL([element.strValue trim])){
            continue;
        }
        [array addObject:element];
    }
    // 释放清理空间
    xmlFreeDoc(doc);
    xmlCleanupParser();
    xmlMemoryDump();
    return array;}

@end
